import requests
import json
from typing import Dict, List, Optional, Tuple
import time

# 轻量缓存（10分钟）
_CACHE_TTL = 600
_POI_CACHE: Dict[Tuple[str, str], Dict] = {}
_ROUTE_CACHE: Dict[Tuple[str, str, str], Dict] = {}
_GEOCODE_CACHE: Dict[str, Tuple[float,float]] = {}

class GaodeAPI:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://restapi.amap.com/v3"
        self.place_url = "https://restapi.amap.com/v5"
        
    def geocode(self, address: str) -> Optional[Tuple[float, float]]:
        """地理编码：将地址转换为经纬度"""
        url = f"{self.base_url}/geocode/geo"
        params = {
            'key': self.api_key,
            'address': address,
            'output': 'json'
        }
        
        # 缓存
        ck = address
        ent = _GEOCODE_CACHE.get(ck)
        if ent:
            return ent
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['geocodes']:
                location = data['geocodes'][0]['location']
                lng, lat = map(float, location.split(','))
                _GEOCODE_CACHE[ck] = (lng, lat)
                return (lng, lat)
        except Exception as e:
            print(f"地理编码失败: {e}")
            
        return None
    
    def get_geocode(self, address: str) -> Optional[Dict]:
        """获取地理编码信息（包含省份等详细信息）"""
        url = f"{self.base_url}/geocode/geo"
        params = {
            'key': self.api_key,
            'address': address,
            'output': 'json'
        }
        
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['geocodes']:
                geocode_info = data['geocodes'][0]
                return {
                    'province': geocode_info.get('province', ''),
                    'city': geocode_info.get('city', ''),
                    'district': geocode_info.get('district', ''),
                    'location': geocode_info.get('location', ''),
                    'formatted_address': geocode_info.get('formatted_address', '')
                }
        except Exception as e:
            print(f"获取地理编码信息失败: {e}")
            
        return None
    
    def get_all_cities(self) -> List[str]:
        """获取全国所有城市列表"""
        # 直接返回扩展的城市列表，避免API调用问题
        return [
            # 直辖市
            '北京', '上海', '天津', '重庆',
            # 省会城市
            '广州', '深圳', '成都', '西安', '武汉', '南京', '杭州', '青岛',
            '厦门', '长沙', '郑州', '合肥', '济南', '福州', '南昌', '石家庄',
            '太原', '呼和浩特', '沈阳', '大连', '长春', '哈尔滨', '昆明', '贵阳',
            '南宁', '海口', '三亚', '兰州', '西宁', '银川', '乌鲁木齐', '拉萨',
            # 安徽省
            '合肥', '芜湖', '蚌埠', '淮南', '马鞍山', '淮北', '铜陵', '安庆',
            '黄山', '滁州', '阜阳', '宿州', '六安', '亳州', '池州', '宣城',
            '东至', '东至县',
            # 广东省
            '广州', '深圳', '佛山', '东莞', '中山', '珠海', '汕头', '湛江',
            '茂名', '肇庆', '惠州', '梅州', '汕尾', '河源', '阳江', '清远',
            '潮州', '揭阳', '云浮',
            # 四川省
            '成都', '自贡', '攀枝花', '泸州', '德阳', '绵阳', '广元', '遂宁',
            '内江', '乐山', '南充', '眉山', '宜宾', '广安', '达州', '雅安',
            '巴中', '资阳',
            # 陕西省
            '西安', '铜川', '宝鸡', '咸阳', '渭南', '延安', '汉中', '榆林',
            '安康', '商洛',
            # 湖北省
            '武汉', '黄石', '十堰', '宜昌', '襄阳', '鄂州', '荆门', '孝感',
            '荆州', '黄冈', '咸宁', '随州', '恩施',
            # 江苏省
            '南京', '无锡', '徐州', '常州', '苏州', '南通', '连云港', '淮安',
            '盐城', '扬州', '镇江', '泰州', '宿迁',
            # 浙江省
            '杭州', '宁波', '温州', '嘉兴', '湖州', '绍兴', '金华', '衢州',
            '舟山', '台州', '丽水',
            # 山东省
            '青岛', '淄博', '枣庄', '东营', '烟台', '潍坊', '济宁', '泰安',
            '威海', '日照', '临沂', '德州', '聊城', '滨州', '菏泽',
            # 辽宁省
            '沈阳', '大连', '鞍山', '抚顺', '本溪', '丹东', '锦州', '营口',
            '阜新', '辽阳', '盘锦', '铁岭', '朝阳', '葫芦岛',
            # 吉林省
            '长春', '吉林', '四平', '辽源', '通化', '白山', '松原', '白城',
            # 黑龙江省
            '哈尔滨', '齐齐哈尔', '鸡西', '鹤岗', '双鸭山', '大庆', '伊春',
            '佳木斯', '七台河', '牡丹江', '黑河', '绥化',
            # 湖南省
            '长沙', '株洲', '湘潭', '衡阳', '邵阳', '岳阳', '常德', '张家界',
            '益阳', '郴州', '永州', '怀化', '娄底',
            # 江西省
            '南昌', '景德镇', '萍乡', '九江', '新余', '鹰潭', '赣州', '吉安',
            '宜春', '抚州', '上饶',
            # 云南省
            '昆明', '曲靖', '玉溪', '保山', '昭通', '丽江', '普洱', '临沧',
            '楚雄', '红河', '文山', '西双版纳', '大理', '德宏', '怒江', '迪庆',
            # 广西省
            '南宁', '柳州', '桂林', '梧州', '北海', '防城港', '钦州', '贵港',
            '玉林', '百色', '贺州', '河池', '来宾', '崇左',
            # 贵州省
            '贵阳', '六盘水', '遵义', '安顺', '毕节', '铜仁',
            # 海南省
            '海口', '三亚', '三沙', '儋州',
            # 河北省
            '石家庄', '唐山', '秦皇岛', '邯郸', '邢台', '保定', '张家口', '承德',
            '沧州', '廊坊', '衡水',
            # 山西省
            '太原', '大同', '阳泉', '长治', '晋城', '朔州', '晋中', '运城',
            '忻州', '临汾', '吕梁',
            # 内蒙古
            '呼和浩特', '包头', '乌海', '赤峰', '通辽', '鄂尔多斯', '呼伦贝尔',
            '巴彦淖尔', '乌兰察布',
            # 宁夏
            '银川', '石嘴山', '吴忠', '固原', '中卫',
            # 青海省
            '西宁', '海东',
            # 甘肃省
            '兰州', '嘉峪关', '金昌', '白银', '天水', '武威', '张掖', '平凉',
            '酒泉', '庆阳', '定西', '陇南',
            # 新疆
            '乌鲁木齐', '克拉玛依', '吐鲁番', '哈密', '昌吉', '博尔塔拉', '巴音郭楞',
            '阿克苏', '克孜勒苏', '喀什', '和田', '伊犁', '塔城', '阿勒泰',
            # 西藏
            '拉萨', '昌都', '山南', '日喀则', '那曲', '阿里', '林芝',
            # 河南省
            '郑州', '开封', '洛阳', '平顶山', '安阳', '鹤壁', '新乡', '焦作',
            '濮阳', '许昌', '漯河', '三门峡', '南阳', '商丘', '信阳', '周口',
            '驻马店', '济源'
        ]
    
    def search_nearby_cities(self, city_name: str) -> List[str]:
        """搜索周边城市"""
        # 使用简单的城市映射，避免复杂的API调用
        nearby_mapping = {
            '大连': ['沈阳', '营口', '丹东'],
            '合肥': ['南京', '武汉', '郑州'],
            '北京': ['天津', '石家庄', '保定'],
            '上海': ['南京', '杭州', '苏州'],
            '广州': ['深圳', '佛山', '东莞'],
            '深圳': ['广州', '东莞', '惠州'],
            '成都': ['重庆', '绵阳', '德阳'],
            '西安': ['咸阳', '宝鸡', '渭南'],
            '武汉': ['黄石', '鄂州', '孝感'],
            '南京': ['苏州', '无锡', '常州'],
            '杭州': ['宁波', '绍兴', '嘉兴'],
            '青岛': ['济南', '烟台', '威海'],
            '长沙': ['株洲', '湘潭', '岳阳'],
            '郑州': ['开封', '洛阳', '新乡'],
            '沈阳': ['大连', '鞍山', '抚顺'],
            '哈尔滨': ['齐齐哈尔', '大庆', '佳木斯'],
            '昆明': ['曲靖', '玉溪', '楚雄'],
            '南宁': ['柳州', '桂林', '梧州'],
            '海口': ['三亚', '儋州', '琼海'],
            '兰州': ['白银', '定西', '临夏'],
            '西宁': ['海东', '海北', '黄南'],
            '银川': ['石嘴山', '吴忠', '固原'],
            '乌鲁木齐': ['昌吉', '克拉玛依', '吐鲁番'],
            '拉萨': ['山南', '日喀则', '林芝'],
            '东至': ['池州', '安庆', '合肥'],
            '东至县': ['池州', '安庆', '合肥'],
            '池州': ['东至', '安庆', '铜陵']
        }
        
        return nearby_mapping.get(city_name, [])
    
    def reverse_geocode(self, lng: float, lat: float) -> Optional[str]:
        """逆地理编码：将经纬度转换为地址"""
        url = f"{self.base_url}/geocode/regeo"
        params = {
            'key': self.api_key,
            'location': f"{lng},{lat}",
            'output': 'json'
        }
        
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['regeocode']:
                return data['regeocode']['formatted_address']
        except Exception as e:
            print(f"逆地理编码失败: {e}")
            
        return None
    
    def _is_coordinate(self, location: str) -> bool:
        """检查字符串是否为坐标格式"""
        try:
            parts = location.split(',')
            if len(parts) == 2:
                float(parts[0])
                float(parts[1])
                return True
        except:
            pass
        return False
    
    def search_poi(self, keyword: str, city: str = None) -> List[Dict]:
        """POI搜索：搜索兴趣点"""
        url = f"{self.base_url}/place/text"
        params = {
            'key': self.api_key,
            'keywords': keyword,
            'output': 'json',
            'extensions': 'all'
        }
        
        if city:
            params['city'] = city
            
        # 简单缓存
        ck = (keyword, city or '')
        ent = _POI_CACHE.get(ck)
        if ent and (time.time() - ent['ts'] < _CACHE_TTL):
            return ent['data']
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['pois']:
                pois = data['pois']
                _POI_CACHE[ck] = {'ts': time.time(), 'data': pois}
                return pois
        except Exception as e:
            print(f"POI搜索失败: {e}")
            
        return []

    def search_nearby_stations(self, lng: float, lat: float, radius: int = 800) -> List[Dict]:
        """在给定坐标附近搜索地铁/铁路站口POI（真实POI，无估算）。
        按距离升序返回，最多20条。
        """
        url = f"{self.base_url}/place/around"
        params = {
            'key': self.api_key,
            'location': f"{lng},{lat}",
            'radius': max(100, min(3000, int(radius or 800))),
            'types': '150500|150200',  # 地铁站|铁路车站
            'sortrule': 'distance',
            'output': 'json'
        }
        try:
            r = requests.get(url, params=params, timeout=6)
            d = r.json()
            if d.get('status') == '1' and d.get('pois'):
                pois = d['pois']
                # 过滤更贴近地铁/轨道/站口
                def _score(p):
                    n = (p.get('name') or '')
                    s = 0
                    if '地铁' in n or '轨道' in n: s += 5
                    if '站' in n: s += 2
                    return -s  # 次排序用
                pois.sort(key=lambda p: (_score(p)))
                return pois
        except Exception as e:
            print(f"附近站点搜索失败: {e}")
        return []
    
    def get_transit_route(self, origin: str, destination: str, 
                         city: str = None) -> List[Dict]:
        """公交路线规划"""
        url = f"{self.base_url}/direction/transit/integrated"
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json',
            'city': city or '全国'
        }
        
        # 缓存
        ck = ('transit', origin, destination)
        ent = _ROUTE_CACHE.get(ck)
        if ent and (time.time() - ent['ts'] < _CACHE_TTL):
            return ent['data']
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['route']:
                trans = data['route']['transits']
                _ROUTE_CACHE[ck] = {'ts': time.time(), 'data': trans}
                return trans
        except Exception as e:
            print(f"公交路线规划失败: {e}")
            
        return []
    
    def get_driving_route(self, origin: str, destination: str) -> List[Dict]:
        """驾车路线规划"""
        url = f"{self.base_url}/direction/driving"
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json'
        }
        
        # 缓存
        ck = ('walking', origin, destination)
        ent = _ROUTE_CACHE.get(ck)
        if ent and (time.time() - ent['ts'] < _CACHE_TTL):
            return ent['data']
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['route']:
                return data['route']['paths']
        except Exception as e:
            print(f"驾车路线规划失败: {e}")
            
        return []
    
    def get_walking_route(self, origin: str, destination: str) -> List[Dict]:
        """步行路线规划"""
        url = f"{self.base_url}/direction/walking"
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json'
        }
        
        try:
            response = requests.get(url, params=params, timeout=10)
            data = response.json()
            
            if data['status'] == '1' and data['route']:
                return data['route']['paths']
        except Exception as e:
            print(f"步行路线规划失败: {e}")
            
        return []
    
    def get_realtime_traffic(self, lng: float, lat: float, radius: int = 1000) -> Dict:
        """获取实时路况"""
        url = f"{self.base_url}/traffic/status/rectangle"
        params = {
            'key': self.api_key,
            'rectangle': f"{lng-0.01},{lat-0.01},{lng+0.01},{lat+0.01}",
            'output': 'json'
        }
        
        try:
            response = requests.get(url, params=params, timeout=10)
            data = response.json()
            
            if data['status'] == '1' and data['trafficinfo']:
                return data['trafficinfo']
        except Exception as e:
            print(f"实时路况获取失败: {e}")
            
        return {}
    
    def get_weather(self, city: str) -> Dict:
        """获取天气信息"""
        url = f"{self.base_url}/weather/weatherInfo"
        params = {
            'key': self.api_key,
            'city': city,
            'output': 'json'
        }
        
        try:
            response = requests.get(url, params=params, timeout=10)
            data = response.json()
            
            if data['status'] == '1' and data['lives']:
                return data['lives'][0]
        except Exception as e:
            print(f"天气信息获取失败: {e}")
            
        return {}
    
    def get_route_info(self, origin: str, destination: str, mode: str = 'driving') -> Dict:
        """获取路线信息（驾车/公交/步行）
        
        Args:
            origin: 起点地址或坐标
            destination: 终点地址或坐标  
            mode: 交通方式 'driving', 'transit', 'walking'
            
        Returns:
            Dict: 包含时间、距离、费用等信息
        """
        if mode == 'driving':
            return self._get_driving_info(origin, destination)
        elif mode == 'transit':
            return self._get_transit_info(origin, destination)
        elif mode == 'walking':
            return self._get_walking_info(origin, destination)
        else:
            return {}
    
    def _get_driving_info(self, origin: str, destination: str) -> Dict:
        """获取驾车路线信息"""
        # 如果origin是地址，先转换为坐标
        if not self._is_coordinate(origin):
            origin_coords = self.geocode(origin)
            if not origin_coords:
                print(f"  ❌ 无法获取起点坐标: {origin}")
                return {}
            origin = f"{origin_coords[0]},{origin_coords[1]}"
        
        # 如果destination是地址，先转换为坐标
        if not self._is_coordinate(destination):
            dest_coords = self.geocode(destination)
            if not dest_coords:
                print(f"  ❌ 无法获取终点坐标: {destination}")
                return {}
            destination = f"{dest_coords[0]},{dest_coords[1]}"
        
        url = f"{self.base_url}/direction/driving"
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json',
            'extensions': 'all',
            'strategy': '1'  # 添加路线策略：1=速度优先，2=费用优先，3=距离优先
        }
        
        # 缓存
        ck = ('driving', origin, destination)
        ent = _ROUTE_CACHE.get(ck)
        if ent and (time.time() - ent['ts'] < _CACHE_TTL):
            return ent['data']
        try:
            response = requests.get(url, params=params, timeout=6)
            data = response.json()
            
            if data['status'] == '1' and data['route'] and data['route']['paths']:
                path = data['route']['paths'][0]  # 取最优路径
                print(f"  ✅ 驾车路线: {int(path['duration']) // 60}分钟, {int(path['distance']) // 1000}公里")
                res = {
                    'duration': int(path['duration']) // 60,  # 转换为分钟
                    'distance': int(path['distance']) // 1000,  # 转换为公里
                    'tolls': path.get('tolls', '0'),
                    'toll_distance': path.get('toll_distance', '0'),
                    'traffic_lights': path.get('traffic_lights', 0),
                    'type': 'driving',
                    'taxi_cost': (data.get('route') or {}).get('taxi_cost', '0')
                }
                _ROUTE_CACHE[ck] = {'ts': time.time(), 'data': res}
                return res
            else:
                print(f"  ❌ 驾车路线API错误: {data.get('info', '未知错误')}")
        except Exception as e:
            print(f"  ❌ 驾车路线获取失败: {e}")
            
        return {}
    
    def _get_transit_info(self, origin: str, destination: str) -> Dict:
        """获取公交路线信息"""
        url = f"{self.base_url}/direction/transit/integrated"
        # 动态解析城市，优先用 destination 所在城市
        geo_dest = self.get_geocode(destination) or {}
        # 如果传入的是坐标或上一步失败，尝试逆地理 + 正地理拿到城市
        if (not geo_dest) and self._is_coordinate(destination):
            try:
                addr = self.reverse_geocode(float(destination.split(',')[0]), float(destination.split(',')[1]))
                if addr:
                    geo_dest = self.get_geocode(addr) or {}
            except Exception:
                pass
        city_name = (geo_dest.get('city') or geo_dest.get('province') or '全国')
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json',
            'city': city_name,
            'extensions': 'all'
        }
        
        try:
            response = requests.get(url, params=params, timeout=10)
            data = response.json()
            
            if data['status'] == '1' and data['route'] and data['route']['transits']:
                transit = data['route']['transits'][0]  # 取最优方案
                
                # 优先使用顶层字段；若缺失，再用分段相加（全部来自高德，未做估算）
                def _to_min(v):
                    try:
                        return int(float(v)) // 60
                    except Exception:
                        return 0
                def _to_km(v):
                    try:
                        return int(float(v)) // 1000
                    except Exception:
                        return 0
                
                total_duration = _to_min(transit.get('duration', 0))
                total_distance = _to_km(transit.get('distance', 0))
                
                segments = []
                subway_found = False
                sum_seg_min = 0
                sum_seg_km = 0
                
                for segment in transit.get('segments', []) or []:
                    if segment.get('bus') is not None:
                        bus = segment['bus']
                        name = ''
                        try:
                            lines = bus.get('buslines') or []
                            if lines:
                                name = str(lines[0].get('name') or '')
                        except Exception:
                            name = ''
                        is_subway = ('地铁' in name) or ('轨道' in name) or ('号线' in name)
                        if is_subway:
                            subway_found = True
                        dmin = _to_min(bus.get('duration', 0))
                        dkm = _to_km(bus.get('distance', 0))
                        sum_seg_min += dmin
                        sum_seg_km += dkm
                        segments.append({'type': 'subway' if is_subway else 'bus', 'name': name, 'duration': dmin, 'distance': dkm})
                    elif segment.get('railway') is not None:
                        railway = segment['railway']
                        rname = str(railway.get('name', '') or '')
                        is_subway2 = ('地铁' in rname) or ('轨道' in rname) or ('号线' in rname)
                        if is_subway2:
                            subway_found = True
                        dmin = _to_min(railway.get('duration', 0))
                        dkm = _to_km(railway.get('distance', 0))
                        sum_seg_min += dmin
                        sum_seg_km += dkm
                        segments.append({'type': 'subway' if is_subway2 else 'railway', 'name': rname, 'duration': dmin, 'distance': dkm})
                    elif segment.get('walking') is not None:
                        walking = segment['walking']
                        dmin = _to_min(walking.get('duration', 0))
                        dkm = _to_km(walking.get('distance', 0))
                        sum_seg_min += dmin
                        sum_seg_km += dkm
                        segments.append({'type': 'walking', 'name': '步行', 'duration': dmin, 'distance': dkm})
                
                if total_duration <= 0 and sum_seg_min > 0:
                    total_duration = sum_seg_min
                if total_distance <= 0 and sum_seg_km > 0:
                    total_distance = sum_seg_km
                
                return {
                    'duration': total_duration,
                    'distance': total_distance,
                    'segments': segments,
                    'type': 'transit',
                    'cost': transit.get('cost', '0'),
                    'has_subway': subway_found
                }
            # 第一次无结果，降级重试为全国
            if city_name != '全国':
                try:
                    params['city'] = '全国'
                    response = requests.get(url, params=params, timeout=10)
                    data = response.json()
                    if data['status'] == '1' and data['route'] and data['route']['transits']:
                        transit = data['route']['transits'][0]
                        def _to_min(v):
                            try:
                                return int(float(v)) // 60
                            except Exception:
                                return 0
                        def _to_km(v):
                            try:
                                return int(float(v)) // 1000
                            except Exception:
                                return 0
                        total_duration = _to_min(transit.get('duration', 0))
                        total_distance = _to_km(transit.get('distance', 0))
                        segments = []
                        subway_found = False
                        sum_seg_min = 0
                        sum_seg_km = 0
                        for segment in transit.get('segments', []) or []:
                            if segment.get('bus') is not None:
                                bus = segment['bus']
                                name = ''
                                try:
                                    lines = bus.get('buslines') or []
                                    if lines:
                                        name = str(lines[0].get('name') or '')
                                except Exception:
                                    name = ''
                                is_subway = ('地铁' in name) or ('轨道' in name) or ('号线' in name)
                                if is_subway:
                                    subway_found = True
                                dmin = _to_min(bus.get('duration', 0))
                                dkm = _to_km(bus.get('distance', 0))
                                sum_seg_min += dmin
                                sum_seg_km += dkm
                                segments.append({'type': 'subway' if is_subway else 'bus', 'name': name, 'duration': dmin, 'distance': dkm})
                            elif segment.get('railway') is not None:
                                railway = segment['railway']
                                rname = str(railway.get('name', '') or '')
                                is_subway2 = ('地铁' in rname) or ('轨道' in rname) or ('号线' in rname)
                                if is_subway2:
                                    subway_found = True
                                dmin = _to_min(railway.get('duration', 0))
                                dkm = _to_km(railway.get('distance', 0))
                                sum_seg_min += dmin
                                sum_seg_km += dkm
                                segments.append({'type': 'subway' if is_subway2 else 'railway', 'name': rname, 'duration': dmin, 'distance': dkm})
                            elif segment.get('walking') is not None:
                                walking = segment['walking']
                                dmin = _to_min(walking.get('duration', 0))
                                dkm = _to_km(walking.get('distance', 0))
                                sum_seg_min += dmin
                                sum_seg_km += dkm
                                segments.append({'type': 'walking', 'name': '步行', 'duration': dmin, 'distance': dkm})
                        if total_duration <= 0 and sum_seg_min > 0:
                            total_duration = sum_seg_min
                        if total_distance <= 0 and sum_seg_km > 0:
                            total_distance = sum_seg_km
                        return {
                            'duration': total_duration,
                            'distance': total_distance,
                            'segments': segments,
                            'type': 'transit',
                            'cost': transit.get('cost', '0'),
                            'has_subway': subway_found
                        }
                except Exception:
                    pass
        except Exception as e:
            print(f"公交路线获取失败: {e}")
            
        return {}
    
    def _get_walking_info(self, origin: str, destination: str) -> Dict:
        """获取步行路线信息"""
        url = f"{self.base_url}/direction/walking"
        params = {
            'key': self.api_key,
            'origin': origin,
            'destination': destination,
            'output': 'json'
        }
        
        # 缓存键
        ck = ('walking', origin, destination)
        ent = _ROUTE_CACHE.get(ck)
        if ent and (time.time() - ent['ts'] < _CACHE_TTL):
            return ent['data']
        
        try:
            response = requests.get(url, params=params, timeout=10)
            data = response.json()
            
            if data['status'] == '1' and data['route'] and data['route']['paths']:
                path = data['route']['paths'][0]
                res = {
                    'duration': int(path['duration']) // 60,  # 转换为分钟
                    'distance': int(path['distance']) // 1000,  # 转换为公里
                    'type': 'walking'
                }
                _ROUTE_CACHE[ck] = {'ts': time.time(), 'data': res}
                return res
        except Exception as e:
            print(f"步行路线获取失败: {e}")
            
        return {}
    
    def get_airport_station_access(self, address: str, transport_hub: str, hub_type: str = 'airport') -> Dict:
        """获取从地址到交通枢纽的接驳信息（仅驾车+公交；优先最近的枢纽）"""
        # 1) 搜索枢纽候选（去掉“客运站”关键字）并选择最近
        search_keywords = {
            'airport': ['机场', '国际机场', '航空港'],
            'railway_station': ['火车站', '高铁站']
        }
        city = transport_hub.replace('机场','').replace('国际机场','').replace('火车站','').replace('高铁站','').replace('站','')
        candidates = []
        
        # 尝试多种搜索方式
        search_terms = [
            transport_hub,  # 直接搜索完整名称
            f"{transport_hub}站",  # 添加站字
            f"{city}南站" if '南站' in transport_hub else transport_hub,  # 如果是南站，尝试城市+南站
        ]
        
        for term in search_terms:
            pois = self.search_poi(term, city)
            # 过滤掉客运站/公交站等
            pois = [p for p in pois if ('机场' in p.get('name','') or '火车站' in p.get('name','') or '高铁' in p.get('name','') or '南站' in p.get('name','')) and ('客运' not in p.get('name',''))]
            if pois:
                candidates.extend(pois[:3])  # 最多取前三个
                break  # 找到就停止
        if not candidates:
            print(f'  ❌ 无法找到交通枢纽位置: {transport_hub}')
            return {}
        # 选择距离address驾车时间最短的一个
        best_loc = None
        best_dur = None
        for poi in candidates:
            loc = poi.get('location')
            if not loc:
                continue
            driving = self.get_route_info(address, loc, 'driving')
            if driving and (best_dur is None or driving.get('duration', 0) < best_dur):
                best_dur = driving.get('duration', 0)
                best_loc = loc
        hub_location = best_loc or candidates[0].get('location')
        if not hub_location:
            return {}
        
        result = {
            'origin': address,
            'destination': transport_hub,
            'hub_type': hub_type,
            'options': {}
        }
        
        # 2) 仅提供驾车和公交（不查步行）；驾车成功即返回
        driving_info = self.get_route_info(address, hub_location, 'driving')
        if driving_info:
            result['options']['driving'] = {
                'duration': driving_info.get('duration', 0),
                'distance': driving_info.get('distance', 0),
                'tolls': driving_info.get('tolls', '0'),
                'description': f"驾车约{driving_info.get('duration', 0)}分钟，{driving_info.get('distance', 0)}公里"
            }
            return result
        
        transit_info = self.get_route_info(address, hub_location, 'transit')
        if transit_info:
            result['options']['transit'] = {
                'duration': transit_info.get('duration', 0),
                'distance': transit_info.get('distance', 0),
                'cost': transit_info.get('cost', '0'),
                'segments': transit_info.get('segments', []),
                'description': f"公交约{transit_info.get('duration', 0)}分钟，{transit_info.get('distance', 0)}公里"
            }
        return result
    
    def _search_transport_hub(self, hub_name: str, hub_type: str) -> str:
        """搜索交通枢纽的准确位置"""
        # 根据枢纽类型添加搜索关键词
        search_keywords = {
            'airport': ['机场', '国际机场', '航空港'],
            'railway_station': ['火车站', '高铁站', '客运站']
        }
        
        keywords = search_keywords.get(hub_type, [hub_name])
        
        # 从hub_name中提取城市名称
        city = hub_name.replace('机场', '').replace('火车站', '').replace('高铁站', '').replace('客运站', '')
        
        for keyword in keywords:
            pois = self.search_poi(f"{hub_name}{keyword}", city)
            if pois:
                # 返回第一个结果的坐标
                location = pois[0].get('location')
                if location:
                    print(f"  🎯 找到交通枢纽: {pois[0].get('name')} at {location}")
                    return location
        
        print(f"  ❌ 未找到交通枢纽: {hub_name}")
        return None  # 如果搜索失败，返回None